/**********************************************************************
*  Copyright (c) 2007 - Victor Jacobs - victor.jacobs@gmail.com
*
*  Permission is hereby granted, free of charge, to any person
*  obtaining a copy of this software and associated documentation
*  files (the "Software"), to deal in the Software without
*  restriction, including without limitation the rights to use,
*  copy, modify, merge, publish, distribute, sublicense, and/or sell
*  copies of the Software, and to permit persons to whom the
*  Software is furnished to do so, subject to the following
*  conditions:
*
*  The above copyright notice and this permission notice shall be
*  included in all copies or substantial portions of the Software.
*
*  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
*  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
*  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
*  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
*  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
*  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
*  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
*  OTHER DEALINGS IN THE SOFTWARE.
**********************************************************************/

using System;
using System.Collections.Generic;
using System.Text;

namespace Vj.MathLibrary.Binary
{
    public class Bit
    {
        private bool myBit;

        public Bit()
        {
            myBit = false;
        }

        public Bit(bool bit)
        {
            myBit = bit;
        }

        public Bit(int bit)
        {
            if (bit == 0)
                myBit = false;
            else if (bit == 1)
                myBit = true;
            else
                throw new ArgumentOutOfRangeException("Bit must be zero or one.");
        }

        public static Bit True
        {
            get { return new Bit(true); }
        }

        public static Bit False
        {
            get { return new Bit(false); }
        }

        public int IntValue
        {
            get
            {
                if (myBit)
                    return 1;
                else
                    return 0;
            }
            set
            {
                if (value == 0)
                    myBit = false;
                else if (value == 1)
                    myBit = true;
                else
                    throw new ArgumentOutOfRangeException("Bit must be zero or one.");
            }
        }

        public bool BoolValue
        {
            get
            { return myBit; }
            set
            { myBit = value; }
        }

        public void Flip()
        {
            myBit = !myBit;
        }

        public static Bit XOR(Bit bit1, Bit bit2)
        {
            if (bit1 == null || bit2 == null)
                throw new ArgumentNullException();

            Bit returnBit = new Bit(0);

            if (bit1.IntValue == 0 && bit2.IntValue == 0) { returnBit.IntValue = 0; }
            else if (bit1.IntValue == 0 && bit2.IntValue == 1) { returnBit.IntValue = 1; }
            else if (bit1.IntValue == 1 && bit2.IntValue == 0) { returnBit.IntValue = 1; }
            else if (bit1.IntValue == 1 && bit2.IntValue == 1) { returnBit.IntValue = 0; }

            return returnBit;
        }

        public static Bit AND(Bit bit1, Bit bit2)
        {
            if (bit1 == null || bit2 == null)
                throw new ArgumentNullException();

            Bit returnBit = new Bit(0);

            if (bit1.IntValue == 0 && bit2.IntValue == 0) { returnBit.IntValue = 0; }
            else if (bit1.IntValue == 0 && bit2.IntValue == 1) { returnBit.IntValue = 0; }
            else if (bit1.IntValue == 1 && bit2.IntValue == 0) { returnBit.IntValue = 0; }
            else if (bit1.IntValue == 1 && bit2.IntValue == 1) { returnBit.IntValue = 1; }

            return returnBit;
        }

        public static Bit OR(Bit bit1, Bit bit2)
        {
            if (bit1 == null || bit2 == null)
                throw new ArgumentNullException();

            Bit returnBit = new Bit(0);

            if (bit1.IntValue == 0 && bit2.IntValue == 0) { returnBit.IntValue = 0; }
            else if (bit1.IntValue == 0 && bit2.IntValue == 1) { returnBit.IntValue = 1; }
            else if (bit1.IntValue == 1 && bit2.IntValue == 0) { returnBit.IntValue = 1; }
            else if (bit1.IntValue == 1 && bit2.IntValue == 1) { returnBit.IntValue = 1; }

            return returnBit;
        }

        public static Bit NOR(Bit bit1, Bit bit2)
        {
            if (bit1 == null || bit2 == null)
                throw new ArgumentNullException();

            Bit returnBit = new Bit(0);

            if (bit1.IntValue == 0 && bit2.IntValue == 0) { returnBit.IntValue = 1; }
            else if (bit1.IntValue == 0 && bit2.IntValue == 1) { returnBit.IntValue = 0; }
            else if (bit1.IntValue == 1 && bit2.IntValue == 0) { returnBit.IntValue = 0; }
            else if (bit1.IntValue == 1 && bit2.IntValue == 1) { returnBit.IntValue = 0; }

            return returnBit;
        }

        public static Bit NAND(Bit bit1, Bit bit2)
        {
            if (bit1 == null || bit2 == null)
                throw new ArgumentNullException();

            Bit returnBit = new Bit(0);

            if (bit1.IntValue == 0 && bit2.IntValue == 0) { returnBit.IntValue = 1; }
            else if (bit1.IntValue == 0 && bit2.IntValue == 1) { returnBit.IntValue = 1; }
            else if (bit1.IntValue == 1 && bit2.IntValue == 0) { returnBit.IntValue = 1; }
            else if (bit1.IntValue == 1 && bit2.IntValue == 1) { returnBit.IntValue = 0; }

            return returnBit;
        }
        
        public static Bit NOT(Bit aBit)
        {
            if (aBit == null)
                throw new ArgumentNullException();

            Bit returnBit = new Bit(0);

                if (aBit.IntValue == 0)
                    returnBit.IntValue = 1;
                else
                    returnBit.IntValue = 0;

            return returnBit;
        }

        public override string ToString()
        {
            string output = this.IntValue.ToString();
            return output;
        }

        public static Bit operator !(Bit aBit)
        {
            Bit temp = new Bit();
            temp.BoolValue = !aBit.BoolValue;
            return temp;
        }

    }
}
